﻿using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Windows;
using System.Windows.Input;
using Microsoft.Practices.Prism.Commands;
using StepsManagerLibrary;
using System.Collections.Generic;
using StepsManagerLibrary.Enum;
using StepsManagerLibrary.Interfaces;
using StepsManagerUILibrary;
using WPF_Example.Helpers;
using WPF_Example.View;

namespace WPF_Example.ViewModel
{
    /// <summary>
    /// ViewModel of the MainWindow.xaml
    /// </summary>
    public class MainViewModel : BaseViewModel
    {
        #region Fields

        /// <summary>
        /// StepsManager
        /// </summary>
        private readonly IStepControlManager<IStepControl> _stepsManager;

        #endregion

        #region Properties

        // CurrentStep control
        private FrameworkElement _currentControl;
        public FrameworkElement CurrentControl
        {
            get
            {
                return _currentControl;
            }
            set
            {
                if (_currentControl != value)
                {
                    _currentControl = value;
                    OnPropertyChanged("CurrentControl");
                }
            }
        }

        // List of observers displayed in the interface
        private IList<FrameworkElement> _observers;
        public IList<FrameworkElement> Observers
        {
            get { return _observers; }
            set
            {
                _observers = value;
                OnPropertyChanged("Observers");
            }
        }

        // Can we move in / from a step
        private string _canMoveResult;
        public string CanMoveResult
        {
            get { return _canMoveResult; }
            set
            {
                _canMoveResult = value;
                OnPropertyChanged("CanMoveResult");
            }
        }

        #endregion

        #region Commands (buttons events)

        #region GoToFirst
        // Command to move to a previous step
        private readonly ICommand _goToFirstCommand;
        public ICommand GoToFirstCommand
        {
            get { return _goToFirstCommand; }
        }

        /// <summary>
        /// Method to call when the GoToFirstCommand is called
        /// </summary>
        private void GoToFirstAction()
        {
            _stepsManager.GoToFirst();
        }

        #endregion

        #region GoToPrevious
        // Command to move to a previous step
        private readonly ICommand _goToPreviousCommand;
        public ICommand GoToPreviousCommand
        {
            get { return _goToPreviousCommand; }
        }

        /// <summary>
        /// Method to call when the GoToPreviousCommand is called
        /// </summary>
        private void GoToPreviousAction()
        {
            _stepsManager.GoToPrevious();
        }

        #endregion

        #region GoToNext
        // Command to move to a next step
        private readonly ICommand _goToNextCommand;
        public ICommand GoToNextCommand
        {
            get { return _goToNextCommand; }
        }

        /// <summary>
        /// Method to call when the GoToNextCommand is called
        /// </summary>
        private void GoToNextAction()
        {
            _stepsManager.GoToNext();
        }

        #endregion

        #region GoToLast
        // Command to move to the Last step
        private readonly ICommand _goToLastCommand;
        public ICommand GoToLastCommand
        {
            get { return _goToLastCommand; }
        }

        /// <summary>
        /// Method to call when the GoToLastCommand is called
        /// </summary>
        private void GoToLastAction()
        {
            _stepsManager.GoToLast();
        }

        #endregion

        #region CanMoveIn
        // Command to check if we can Move to the current Step
        private readonly ICommand _canMoveInCommand;
        public ICommand CanMoveInCommand
        {
            get { return _canMoveInCommand; }
        }

        /// <summary>
        /// Method to call when the canMoveInCommand is called
        /// </summary>
        private void CanMoveInAction()
        {
            CanMoveResult = (_stepsManager.CurrentStep.CanMoveIn()).ToString();
        }

        #endregion

        #region CanMoveOut
        // Command to check if we can Move to the current Step
        private readonly ICommand _canMoveOutCommand;
        public ICommand CanMoveOutCommand
        {
            get { return _canMoveOutCommand; }
        }

        /// <summary>
        /// Method to call when the canMoveOutCommand is called
        /// </summary>
        private void CanMoveOutAction()
        {
            CanMoveResult = (_stepsManager.CurrentStep.CanMoveOut()).ToString();
        }

        #endregion

        #region CanMoveOut

        #endregion

        #endregion

        #region Constructors

        /// <summary>
        /// Create a MainViewModel to be used to manage a StepManager
        /// </summary>
        public MainViewModel()
        {
            // Creation of a collection of UIElement that will display
            // information related with the StepControls
            Observers = new ObservableCollection<FrameworkElement>();

            // Creation of the commands
            _goToFirstCommand = new DelegateCommand(GoToFirstAction);
            _goToPreviousCommand = new DelegateCommand(GoToPreviousAction);
            _goToNextCommand = new DelegateCommand(GoToNextAction);
            _goToLastCommand = new DelegateCommand(GoToLastAction);

            _canMoveInCommand = new DelegateCommand(CanMoveInAction);
            _canMoveOutCommand = new DelegateCommand(CanMoveOutAction);

            // Creation of the step manager
            _stepsManager = new StepControlManager<IStepControl>();
            // Registering the event to know set the value of the CurrentControl when
            // adding an element or a list of elements to the step manager
            _stepsManager.PropertyChanged += StepManagerOnPropertyChanged;

            // Creation of the StepControls

            // Step1 and Step 2 are classic WPF UserControl
            Step1View step1 = new Step1View("Step 1");
            Step2View step2 = new Step2View("Step 2");

            // Step 3 is a Hosted WPF UserControl
            UntypedUserControl step3 =
                new UntypedUserControl(new Step3WPFHostedView("Step 3"));

            // Step 4 is a Hosted Winform Control
            UntypedUserControl step4 =
                new UntypedUserControl(new Step4WinformHostedView("Step 4"));

            // Step 5 is again a classif WPF UserControl but with multiple observers
            Step5View step5 = new Step5View("Step 5");


            // Registering the observers (2 different to show what can be done)
            step1.Attach(AddUIObserver(step1));
            step2.Attach(AddUIObserver(step2));
            step3.Attach(AddUIObserver(step3));
            step4.Attach(AddUIObserver(step4));
            step5.Attach(AddUIObserver(step5));
            step5.Attach(new MessageBoxObserver(step5));

            // Adding the IStepControls to the step manager
            _stepsManager.AddStep(step1);
            _stepsManager.AddStep(step2);
            _stepsManager.AddStep(step3);
            _stepsManager.AddStep(step4);
            _stepsManager.AddStep(step5);
        }

        #endregion

        #region Events

        /// <summary>
        /// Event informing that a Property has changed in the StepsManager
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="propertyChangedEventArgs"></param>
        private void StepManagerOnPropertyChanged(object sender, PropertyChangedEventArgs propertyChangedEventArgs)
        {
            // When the CurrentStep has been updated, change the CurrentControl
            // of the MainWindow
            if (propertyChangedEventArgs.PropertyName == "CurrentStep")
            {
                CurrentControl = _stepsManager.CurrentStep as FrameworkElement;
            }
        }

        #endregion

        #region Methods

        /// <summary>
        /// Create an observer which is a UserControl and will be added
        /// to the list of observer controls 
        /// </summary>
        /// <param name="step">Step related with the observer</param>
        /// <returns></returns>
        private IObserver<StepControlStateEnum> AddUIObserver(IStepControl step)
        {
            ObserverViewModel observerViewModel = new ObserverViewModel(step.Title);
            ObserverView observerView = new ObserverView(observerViewModel);

            _observers.Add(observerView);

            return observerViewModel;
        }

        #endregion
    }
}
